package org.linitly;

import org.dom4j.DocumentException;
import org.linitly.enums.FileTypeEnum;
import org.linitly.util.FileCopyUtil;

import java.io.File;
import java.io.IOException;

/**
 * @author: linxiunan
 * @date: 2021/5/28 15:47
 * @descrption: java文件修改
 */
public class JavaProjectDeal {

    private static final String JAVA_FILE_SUFFIX = ".java";
    private static final String XML_FILE_SUFFIX = ".xml";
    private static final String YML_FILE_SUFFIX = ".yml";
    private static final String YAML_FILE_SUFFIX = ".yaml";
    private static final String PROPERTIES_FILE_SUFFIX = ".properties";

    private static final String POM_XML_FILE_NAME = "pom.xml";

    private static final String DEFAULT_JAVA_PROJECT_NAME = "linitly-boot";
    public static final String DEFAULT_PACKAGE_NAME = "org.linitly.boot";

    private static final String TARGET_DIR_NAME = "target";

    public static void deal(String projectName, String packageName, File projectPathFile, File newProjectParentDirFile) throws IOException, DocumentException {

        File newProjectPathFile = FileCopyUtil.createProjectDir(projectName, newProjectParentDirFile);
        File[] listFiles = projectPathFile.listFiles();
        if (listFiles == null || listFiles.length < 1) {
            System.out.println("java project path error, no file under the path");
            System.exit(-1);
            return;
        }
        traverse(listFiles, newProjectPathFile, projectName, packageName);
    }

    private static void copyDir(File dir, File newProjectPathFile, String projectName, String packageName) throws IOException, DocumentException {
        // 如果是target目录，不处理
        if (isTargetDir(dir)) {
            return;
        }
        // 判断是否为main/java包
        if (isJavaDir(dir)) {
            File[] files = updateJavaDir(dir, newProjectPathFile, packageName);
            if (files[0] != null) traverse(files[0].listFiles(), files[1], projectName, packageName);  //
            return;
        }
        File destDir = FileCopyUtil.copyDir(dir, newProjectPathFile);
        File[] listFiles = dir.listFiles();
        traverse(listFiles, destDir, projectName, packageName);
    }

    private static void traverse(File[] listFiles, File destDir, String projectName, String packageName) throws IOException, DocumentException {
        if (listFiles == null || listFiles.length < 1) return;

        for (int i = 0; i < listFiles.length; i++) {
            if (listFiles[i].isDirectory()) {
                copyDir(listFiles[i], destDir, projectName, packageName);
            } else if (listFiles[i].isFile()){
                copyFile(listFiles[i], destDir, projectName, packageName);
            }
        }
    }

    private static void copyFile(File sourceFile, File destDirPath, String projectName, String packageName) throws IOException, DocumentException {
        FileTypeEnum fileType = getFileType(sourceFile.getName());
        switch (fileType) {
            case JAVA:
            case XML:
                JavaFileCopy.copyJavaFile(sourceFile, destDirPath, packageName, projectName);
                break;
            case POM:
                PomFileCopy.copyPomFile(sourceFile, destDirPath, projectName, packageName);
                break;
            case PROPERTIES:
            case YML:
            case YAML:
            case OTHER:
                FileCopyUtil.copyFile(sourceFile, destDirPath);
                break;
        }
    }

    private static boolean isJavaDir(File dir) {
        return dir.getName().equals("java") && dir.getParentFile().getName().equals("main");
    }

    private static boolean isTargetDir(File dir) {
        return dir.getName().equals(TARGET_DIR_NAME);
    }

    private static FileTypeEnum getFileType(String fileName) {
        if (isJavaFile(fileName)) return FileTypeEnum.JAVA;
        if (isPomFile(fileName)) return FileTypeEnum.POM;
        if (isXmlFile(fileName)) return FileTypeEnum.XML;
        if (isYmlFile(fileName)) return FileTypeEnum.YML;
        if (isYamlFile(fileName)) return FileTypeEnum.YAML;
        if (isPropertiesFile(fileName)) return FileTypeEnum.PROPERTIES;
        return FileTypeEnum.OTHER;
    }

    private static boolean isPomFile(String fileName) {
        return fileName.equals(POM_XML_FILE_NAME);
    }

    private static boolean isJavaFile(String fileName) {
        return fileName.endsWith(JAVA_FILE_SUFFIX);
    }

    private static boolean isXmlFile(String fileName) {
        return fileName.endsWith(XML_FILE_SUFFIX);
    }

    private static boolean isYmlFile(String fileName) {
        return fileName.endsWith(YML_FILE_SUFFIX);
    }

    private static boolean isYamlFile(String fileName) {
        return fileName.endsWith(YAML_FILE_SUFFIX);
    }

    private static boolean isPropertiesFile(String fileName) {
        return fileName.endsWith(PROPERTIES_FILE_SUFFIX);
    }

    /**
     * 修改包名(目录名)
     */
    private static File[] updateJavaDir(File javaDir, File destDir, String packageName) throws IOException {
        // 复制java目录
        File newJavaDir = FileCopyUtil.copyDir(javaDir, destDir);

        String[] packages = getPackages(packageName);
        StringBuilder path = new StringBuilder();
        for (int i = 0; i < packages.length; i++) {
            path.append("/");
            path.append(packages[i]);
        }
        String newPackageBasePath = newJavaDir.getPath() + path.toString();
        File newPackageBase = new File(newPackageBasePath);
        if (!newPackageBase.exists()) {
            boolean mkSuccess = newPackageBase.mkdirs();
            if (!mkSuccess) {
                System.out.println("create java project base package error");
                System.exit(0);
            }
        }

        File operatorDir = null;
        String operatorDirName = getOperatorDirName(DEFAULT_PACKAGE_NAME);

        File[] listFiles = javaDir.listFiles();
        if (listFiles == null || listFiles.length < 1) return null;
        for (int i = 0; i < listFiles.length; i++) {
            if (listFiles[i].isFile()) FileCopyUtil.copyFile(listFiles[i], newJavaDir);
            //
            if (listFiles[i].isDirectory()) {
                if (listFiles[i].getName().equals(operatorDirName)) {
                    operatorDir = listFiles[i];
                } else {
                    operatorDir = getOperateDir(listFiles[i], operatorDirName);
                }
            }
        }
        return new File[]{operatorDir, newPackageBase};
    }

    private static File getOperateDir(File dir, String operatorDirName) {
        File[] listFiles = dir.listFiles();
        if (listFiles == null || listFiles.length < 1) return null;
        for (int i = 0; i < listFiles.length; i++) {
            if (listFiles[i].isDirectory()) {
                if (listFiles[i].getName().equals(operatorDirName)) {
                    return listFiles[i];
                } else {
                    return getOperateDir(listFiles[i], operatorDirName);
                }
            }
        }
        return null;
    }

    private static String[] getPackages(String packageName) {
        return packageName.split("\\.");
    }

    private static String getOperatorDirName(String packageName) {
        String[] packages = packageName.split("\\.");
        return packages[packages.length - 1];
    }
}
